//
//  WLProxyTask.m
//  WLProxy
//
//  Created by wangpeng on 2021/7/23.
//

#import "WHWLProxyTask.h"
#import "wlproxy_invoker.h"
#import "wlproxy_request.h"
#import "wlproxy_define.h"
#import "wherr.h"

//==============================================================================

// 上传/下载回调函数
static int OnProcessCB(const char* session,
                       int         command,
                       const char* result,
                       const char* custom,
                       LPARAM      lParam);

//==============================================================================

@interface WHWLProxyTask ()

@property (nonatomic, assign) wlproxy::CInvoker *invoker;

@property (nonatomic, assign) wlproxy::CRequest *request;

@property (nonatomic, assign) NSStringEncoding encoding;

@property (nonatomic, assign) WLProxyTaskMethod method;

@property (nonatomic, copy) NSString *params;

@property (nonatomic, copy) void(^progressBlock)(NSString *result);
@property (nonatomic, copy) void(^successBlock) (NSString *result);
@property (nonatomic, copy) void(^failureBlock) (NSString *result);

@end

@implementation WHWLProxyTask

- (void)dealloc
{
    [self stopTask];
}

+ (WHWLProxyTask *)taskWithSession:(NSString *)session
                          config:(NSString *)config
                          params:(NSString *)params
                          custom:(NSString *)custom
                          method:(WLProxyTaskMethod)method
                        progress:(void (^)(NSString *result))progress
                         success:(void (^)(NSString *result))success
                         failure:(void (^)(NSString *result))failure
{
    WHWLProxyTask *task = [WHWLProxyTask taskWithSession:session
                                              config:config
                                              params:params
                                              custom:custom
                                              method:method];
    task.progressBlock = progress;
    task.successBlock  = success;
    task.failureBlock  = failure;
    
    return task;
}

+ (WHWLProxyTask *)taskWithSession:(NSString *)session
                          config:(NSString *)config
                          params:(NSString *)params
                          custom:(NSString *)custom
                          method:(WLProxyTaskMethod)method
{
    if (!session || session.length <= 0 ||
        !config || config.length <= 0 ||
        !params || params.length <= 0)
    {
        return nil;
    }
    
    WHWLProxyTask *task = [[WHWLProxyTask alloc] init];
    
    task.encoding = CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000);
    const char *sess = [session cStringUsingEncoding:task.encoding];
    const char *conf = [config cStringUsingEncoding:task.encoding];
    const char *cust = [custom cStringUsingEncoding:task.encoding];
    
    // 初始化任务
    wlproxy::CInvoker *invoker = new wlproxy::CInvoker();
    int ret = invoker->Initialize(sess);
    
    // 创建请求
    wlproxy::CRequest *request = NULL;
    ret = invoker->CreateRequest(conf, cust, request);
    
    if (ret != 0)
    {
        task = nil;
    }
    else
    {
        task.invoker = invoker;
        task.request = request;
        task.method = method;
        task.params = params;
    }
    
    return task;
}

- (int)requestTask
{
    int ret = -1;
    
    if (self.invoker->IsExistRequest(self.request))
    {
        const char *params = [self.params cStringUsingEncoding:self.encoding];
        LPARAM lpCB = (LPARAM)(__bridge void *)self;
        
        switch (self.method)
        {
            case WLProxyTaskMethodAsyncGet:
            {
                ret = self.request->StartGet(params, OnProcessCB, lpCB);
                if (ret != 0)
                {
                    NSString *msg = [NSString stringWithFormat:@"<info><error_code>%d</error_code><error_msg>请求失败</error_msg></info>", ret];
                    [self checkTaskValid:ret withErrorMsg:msg];
                }
            }
                break;
                
            case WLProxyTaskMethodAsyncPut:
            {
                ret = self.request->StartPut(params, OnProcessCB, lpCB);
                if (ret != 0)
                {
                    NSString *msg = [NSString stringWithFormat:@"<info><error_code>%d</error_code><error_msg>请求失败</error_msg></info>", ret];
                    [self checkTaskValid:ret withErrorMsg:msg];
                }
            }
                break;
                
            case WLProxyTaskMethodSyncGet:
            {
                char *result = NULL;
                ret = self.request->Get(params, OnProcessCB, lpCB, result);
                [self syncFinishTask];
                if (ret != 0)
                {
                    NSString *datas = [NSString stringWithCString:result encoding:self.encoding];
                    [self checkTaskValid:ret withErrorMsg:datas];
                }
            }
                break;
                
            case WLProxyTaskMethodSyncPut:
            {
                char *result = NULL;
                ret = self.request->Put(params, OnProcessCB, lpCB, result);
                [self syncFinishTask];
                if (ret != 0)
                {
                    NSString *datas = [NSString stringWithCString:result encoding:self.encoding];
                    [self checkTaskValid:ret withErrorMsg:datas];
                }
            }
                break;
                
            default:
                break;
        }
        
    }
    
    return ret;
}

// 错误的话直接block返回
- (void)checkTaskValid:(NSInteger)ret withErrorMsg:(NSString*)msg
{
    if (ret != 0 && ret != 26)
    {
        if (self.failureBlock)
        {
            self.failureBlock(msg);
        }
    }
}

- (void)stopTask
{
    if (self.request)
    {
        if (self.invoker->IsExistRequest(self.request))
        {
            self.request->Abort();
            self.invoker->DestroyRequest(self.request);
            self.request = NULL;
        }
        self.invoker->Terminate();
        delete self.invoker;
        self.invoker = NULL;
    }
}

- (void)syncFinishTask
{
    if (self.request)
    {
        if (self.invoker->IsExistRequest(self.request))
        {
            self.invoker->DestroyRequest(self.request);
            self.request = NULL;
        }
        self.invoker->Terminate();
        delete self.invoker;
        self.invoker = NULL;
    }
}

// 异步任务需要在任务开启线程释放
- (void)asyncFinishTask
{
//    dispatch_async(dispatch_get_main_queue(), ^
//    {
        if (self.request)
        {
            if (self.invoker->IsExistRequest(self.request))
            {
                if (self.method == WLProxyTaskMethodAsyncGet)
                {
                    self.request->StopGet();
                }
                else if (self.method == WLProxyTaskMethodAsyncPut)
                {
                    self.request->StopPut();
                }
                self.invoker->DestroyRequest(self.request);
                self.request = NULL;
            }
            self.invoker->Terminate();
            delete self.invoker;
            self.invoker = NULL;
        }
//    });
}

//==============================================================================

static int OnProcessCB(const char* session,
                       int         command,
                       const char* result,
                       const char* custom,
                       LPARAM      lParam)
{
    WHWLProxyTask *task = (__bridge WHWLProxyTask *)(void *)lParam;
    NSString *datas = [NSString stringWithCString:result encoding:task.encoding];
    
    switch (command)
    {
        case WLP_INVOKER_CMD_BEGIN:
        {
            NSLog(@"begin datas = %@", datas);
        }
            break;

        case WLP_INVOKER_CMD_END:
        {
            dispatch_async(dispatch_get_main_queue(), ^
            {
                if (task.method == WLProxyTaskMethodAsyncGet ||
                    task.method == WLProxyTaskMethodAsyncPut)
                {
                    [task asyncFinishTask];
                }
                if (datas)
                {
                    if (task.successBlock)
                    {
                        task.successBlock(datas);
                    }
                }
                else
                {
                    if (task.failureBlock)
                    {
                        task.failureBlock(datas);
                    }
                }
            });
        }
            break;
            
        case WLP_INVOKER_CMD_FAILED:
        {
            dispatch_async(dispatch_get_main_queue(), ^
            {
                if (task.method == WLProxyTaskMethodAsyncGet ||
                    task.method == WLProxyTaskMethodAsyncPut)
                {
                    [task asyncFinishTask];
                }
                if (task.failureBlock)
                {
                    task.failureBlock(datas);
                }
            });
        }
            break;
            
        case WLP_INVOKER_CMD_STEP:
        {
            dispatch_async(dispatch_get_main_queue(), ^
            {
                if (datas)
                {
                    if (task.progressBlock)
                    {
                        task.progressBlock(datas);
                    }
                }
                else
                {
                    if (task.method == WLProxyTaskMethodAsyncGet ||
                        task.method == WLProxyTaskMethodAsyncPut)
                    {
                        [task asyncFinishTask];
                    }
                    if (task.failureBlock)
                    {
                        task.failureBlock(datas);
                    }
                }
            });
        }
            break;
            
        default:
            break;
    }
    
    return 0;
}

@end
